/*
 * Copyright (c) 2011, Gerold Roth
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * * Neither the name of the gradecalculator.net nor the
 *   names of its contributors may be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */
package netgradecalculator.plugin.importer.hsrw.lsf.pdf;

import java.util.LinkedList;
import java.util.List;

import net.gradecalculator.plugin.importer.data.ImportedExaminationResult;
import net.gradecalculator.plugin.importer.data.UniversitySemester;

public class LsfPdfParser {
	private final String resultStartIdentificator = "^\\d+ .+";
	private final String resultEndIdentificator = ".+ [WS]S \\d{4} .+ [A-Z]{2}.+$";
	private final String resultExpression = "^\\d+ .+ [WS]S \\d{4}.* [A-Z]{2}.+$";
	private final String resultPassedExpression = "^\\d+ .+ [WS]S \\d{4} .+ BE.+$";
	private final String resultsHeader = "^PrNr Pr.*fungstext Semester Note Status Credits.*$";
	private final String pageExpression = "^Seite \\d+$";
	
	private final String[] rows;
	
	private final String courseOfStudies;
	private final String universityName = "Hochschule Ravensburg-Weingarten";
	private final String studentName;
	private final String matriculationNumber;
	private final String degree;
	private final String studiRegulationVersion = null;
	private final String lowestSemester;
	private final List<ImportedExaminationResult> results;

	/**
	 * This constructor parse a String with the design of a PDF, generated by the LSF system, to useful parameters.
	 * @param fileContent content of a grades list, generated PDF file, by the LSF system, read to a String
	 */
	public LsfPdfParser(final String fileContent)
	{
		rows = getRows(fileContent);

		final int firstExaminationRow = getFirstExaminationRow();
		if (firstExaminationRow < 0) {
			throw new IllegalArgumentException("No compatible PDF file");
		}
		
		courseOfStudies = getLineData("Studiengang: ");
		studentName = getName();	
		matriculationNumber = getLineData("Matrikelnummer: ");
		degree = getLineData("(angestrebter) Abschluss: ");
		results = new LinkedList<ImportedExaminationResult>();
		
		int currentRow = firstExaminationRow;
		UniversitySemester semester = null;
		while (!isExaminationEnd(currentRow)) {
			if (isExaminationPassed(currentRow)) {
				final ImportedExaminationResult result = LsfGradeParserUtil.createResult(courseOfStudies, rows[currentRow]);
				final UniversitySemester currentSemester = new UniversitySemester(result.getSemester());
				if ((semester == null) || (semester.compareTo(currentSemester) > 0)) {
					semester = currentSemester;
				}
				results.add(result);
			}
			currentRow++;
		}
		
		if (semester != null) {
			lowestSemester = semester.toString();
		} else {
			lowestSemester = "";
		}
	}	
	
	private String[] getRows(final String text)
	{
		final List<String> buffer = new LinkedList<String>();
		
		boolean resultsEnabled = false;
		final String[] lines = text.split("\n");
		for (int i = 0; i < lines.length; i++) {
			if (lines[i] == null) {
				continue;
			}
			
			final String line = lines[i].trim();
			if (!resultsEnabled) {
				if (line.matches(resultsHeader)) {
					resultsEnabled = true;
				}
				buffer.add(line);
				continue;
			}
			
			if ((line.matches(resultExpression)) || (!line.matches(resultStartIdentificator))) {
				buffer.add(line);
				continue;
			}
			
			int lastIndex = -1;
			String effectiveLine = line;
			for (int j = i + 1; j < lines.length; j++) {
				final String additionalLine = lines[j].trim();
				effectiveLine = effectiveLine + " " + additionalLine;
				if (additionalLine.matches(resultEndIdentificator)) {
					lastIndex = j;
					break;
				}
			}
			
			if (lastIndex < 0) {
				buffer.add(line);
				continue;
			}
			
			buffer.add(effectiveLine);
			for (int j = i + 1; j <= lastIndex; j++) {
				lines[j] = null;
			}
		}
		
		final String[] result = new String[buffer.size()];
		for (int i = 0; i < result.length; i++) {
			result[i] = buffer.get(i);
		}
		
		return result;
	}
	
	private boolean isRowExaminationHeadRow(final int i)
	{
		final String row = rows[i];
		return (row.matches(resultsHeader));
	}
	
	private boolean isExaminationPassed(final int i)
	{
		return (rows[i].matches(resultPassedExpression));
	}
	
	private boolean isExaminationResult(final int i)
	{
		return (rows[i].matches(resultExpression));
	}	
	
	private boolean isExaminationEnd(final int i)
	{
		if (isExaminationResult(i)) {
			return false;
		}
		if (isRowExaminationHeadRow(i)) {
			return false;
		}
		if (rows[i].matches(pageExpression)) {
			return false;
		}
		
		return true;
	}
	
	private String getName()
	{
		for (int i = 0; i < rows.length - 1; i++) {
			final String row = rows[i];
			if (row.equals("Herrn") || row.equals("Frau"))  {
				return rows[i+1];
			}
		}
		
		return "";
	}
	
	private String getLineData(final String lineData)
	{
		for (int i = 0; i < rows.length - 1; i++) {
			final String row = rows[i];
			if (row.startsWith(lineData))  {
				return row.substring(lineData.length());
			}
		}
		
		return "";
	}

	private int getFirstExaminationRow()
	{
		for (int i = 0; i < rows.length; i++) {
			if (isRowExaminationHeadRow(i)) {
				return i + 1;
			}
		}
		
		return -1;
	}

	public String getUniversityName() {
		return universityName;
	}

	public String getDegree() {
		return degree;
	}

	public String getStudentName() {
		return studentName;
	}

	public String getStudiRegulationVersion() {
		return studiRegulationVersion;
	}

	public String getLowestSemester() {
		return lowestSemester;
	}

	public List<ImportedExaminationResult> getResults() {
		return results;
	}
	
	public String getCourseOfStudies()
	{
		return courseOfStudies;
	}

	public String getMatriculationNumber() {
		return matriculationNumber;
	}
	
}
